<?php

class CValidatorFactory{
	
	private $breakValid;
	
	public function __construct(){
		$this->breakValid = false;
	}
	
	/**
	 * Funcion que retorna las validaciones que se aplicaran al arreglo en base al modelo dado
	 * @param CModelField $model Modelo donde se tomaran valores de verificacion
	 * @param Array $array Lista de opciones 
	 */
	public function execute($model, $array){
		$array = $this->evalValid($model, $array);
		return $array;
	}
	
	/**
	 * Funcion recursiva para barrer tags de validacion
	 * @param CModelField $model Modelo del cual seran obtenidas las reglas de validacion
	 * @param Array $array Arreglo de validaciones en turno
	 */
	private function evalValid($model, $array){
		
		//Si esta activa rompe ejecucion
		if($breakValid){ return array(); }
		
		$required = false;
		$validations = array();
		
		foreach($array as $valid => $valid_params){

			if($this->breakValid == true){ return $validations; }

			//Verifica si es Trigger
			if($valid == CValidTag::Trigger){
				//Ejecuta trigger
				$trigger_array = $this->evalTrigger($model, $valid_params);
				//Valida resultado de trigger
				if(count($trigger_array)>0){
					foreach($trigger_array as $opt => $opt_params){
						$validations = $this->addValidation($validations, $opt, $opt_params);
					}
				}
			}
			
			if($valid == CValidTag::BreakValid){
				$this->breakValid = true;
				return $validations;
			}
			$validations = $this->addValidation($validations, $valid, $valid_params);
		}
	
		return $validations;
	}
	
	/**
	 * Funcion para evaluar la detonacion de un Trigger comparativo
	 * @param CModelField $model Modelo del cual se estan obteniedo las validaciones
	 * @param Array $params Arreglo de opciones en turno
	 */
	private function evalTrigger($model, $params){
		$validations = array();
		
		foreach($params as $trigger => $trigger_params){
			//Obtiene el campo
			$field_array = split("#", $trigger);
			//Valor actual del campo que detona trigger
			$field_value = $model->$field_array[1]->value;
			//Busca valor de comparacion de trigger
			$values = $this->containTag($trigger_params, CValidTag::Value);
			//Busca si la condicion se cumple
			if(in_array($field_value, $values)){
				//El trigger se detona
				$validations = array_merge($validations, $this->evalValid($model, $trigger_params));
			}
			
			if($this->breakValid == true){
				return $validations;
			}
		}
		return $validations;
	}
	
	/**
	 * Verifica si existe un tag dado en el arreglo
	 * @param Array $params Arreglo donde se buscara
	 * @param CValidTag $tag Tag a buscar.
	 */
	private function containTag($params, $tag){
		foreach($params as $opt => $val){
			if($opt == $tag){
				return $val;
			}
		}
		return false;
	}
	
	/**
	 * Agrega Tags de validacion validos a un arreglo
	 * @param Array $array Arreglo donde se desa insertar el tag
	 * @param CValidTag $tag Tag a insertar
	 * @param Array $tag_params Opciones del tag
	 */
	private function addValidation($array, $tag, $tag_params){
		
		switch($tag){
			case CValidTag::BreakValid:
			case CValidTag::Trigger:
			case CValidTag::Value:
			case CValidTag::Mask:
				return $array;
		}

		$array[$tag] = $tag_params;
		return $array;
	}
}